package Utils;

import Utils.BooleanUtil;
import Utils.DateUtil;
import Utils.MapUtil;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.DateConverter;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Map2BeanUtil {
    private static SimpleDateFormat format = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss");


    public static <T> T mapToObject(Map<String, Object> map, T result)
            throws InstantiationException, IllegalAccessException, IllegalArgumentException, ParseException {


        map = MapUtil.getLowerKeyFromMap(map);


        Field[] fields = result.getClass().getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true);

            String strName = field.getName().toLowerCase();

            if (map.containsKey(strName)) {
                Object o = map.get(strName);

                if (o != null && !o.toString().equals("")) {

                    if (o instanceof Date) {
                        String value = format.format(o);
                        field.set(result, format.parse(value));
                    } else if (o instanceof Timestamp) {

                        String value = format.format(o);
                        field.set(result, format.parse(value));
                    } else {

                        field.set(result, o);
                    }


                }

            } else if (map.containsKey(strName.toUpperCase())) {

                Object o = map.get(strName.toUpperCase());

                if (o != null && !o.toString().equals("")) {

                    field.set(result, o);
                }

            }

        }

        return result;
    }


    public static <T> T mapToObject(Map<String, Object> map, Class<T> clazz) {

        if (map == null) {
            return null;
        }

        map = MapUtil.getLowerKeyFromMap(map);

        T obj = null;
        try {
            // 使用newInstance来创建对象
            obj = clazz.newInstance();
            // 获取类中的所有字段
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                // 当字段使用private修饰时，需要加上
                field.setAccessible(true);

                if (map.containsKey(field.getName().toLowerCase())) {
                    // 获取参数类型名字
                    String filedTypeName = field.getType().getName();
                    Object o = map.get(field.getName().toLowerCase());

                    if (o != null && o.toString().length() > 0&&!o.toString().equalsIgnoreCase("null")) {

                        String value = o.toString();

                            // 判断是否为时间类型，使用equalsIgnoreCase比较字符串，不区分大小写
                            // 给obj的属性赋值
                            if (filedTypeName.equalsIgnoreCase("java.util.date")) {

                                if(o  instanceof Date)
                                {
                                    String datevalue = format.format(o);
                                    field.set(obj,format.parse(datevalue));
                                }
                                else {
                                    field.set(obj, format.parse(value));
                                }

                            } else if (filedTypeName.equalsIgnoreCase("java.lang.boolean") || filedTypeName.equalsIgnoreCase("boolean")) {

                                field.set(obj, BooleanUtil.toBoolean(value));

                            } else if (filedTypeName.equalsIgnoreCase("int") || filedTypeName.equalsIgnoreCase("java.lang.integer")) {

                                field.set(obj, Integer.parseInt(value));

                            } else if (filedTypeName.equalsIgnoreCase("double") || filedTypeName.equalsIgnoreCase("java.lang.double")) {

                                field.set(obj, Double.parseDouble(value));

                            } else if (filedTypeName.equalsIgnoreCase("float") || filedTypeName.equalsIgnoreCase("java.lang.float")) {

                                field.set(obj, Float.parseFloat(value));

                            } else if (filedTypeName.equalsIgnoreCase("BigDecimal")) {

                                field.set(obj, BigDecimal.valueOf(Double.parseDouble(value)));

                            }

                            else if (filedTypeName.equalsIgnoreCase("java.util.list")) {


                                List list = (List) o;
                                if (!list.isEmpty()) {
                                    Object listvalue = list.get(0);

                                    if (listvalue.getClass().equals(String.class)) {
                                        field.set(obj, (List<String>) o);
                                    } else if (listvalue.getClass().equals(int.class)
                                            || listvalue.getClass().equals(Integer.class)) {
                                        field.set(obj, (List<Integer>) o);
                                    } else if (listvalue.getClass().equals(double.class)
                                            || listvalue.getClass().equals(Double.class)) {
                                        field.set(obj, (List<Double>) o);
                                    } else if (listvalue.getClass().equals(float.class)
                                            || listvalue.getClass().equals(Float.class)) {
                                        field.set(obj, (List<Float>) o);
                                    } else if (listvalue.getClass().equals(java.util.Date.class)) {
                                        field.set(obj, (List<java.util.Date>) o);
                                    }

                                }
                            }

                            else {
                                field.set(obj, o);
                            }

                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }



    public static <T> T map2Bean(Class<T> clazz, Map<String, Object> map) {

        try {

            T object = clazz.newInstance();
            // 处理时间格式
            DateConverter dateConverter = new DateConverter();
            // 设置日期格式
            dateConverter.setPatterns(new String[] { "yyyy-MM-dd HH:mm:ss" });
            // 注册格式
            ConvertUtils.register(dateConverter, java.util.Date.class);
            // 封装数据
            BeanUtils.populate(object, map);

            return object;
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return null;
    }

    public static <T> T map2Bean2(Class<T> beanCls,Map<String, Object> mp)
            throws Exception, IllegalArgumentException, InvocationTargetException {
        T t = null;
        try {

            mp = MapUtil.getUpperKeyFromMap(mp);
            BeanInfo beanInfo = Introspector.getBeanInfo(beanCls);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

            t = beanCls.newInstance();

            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();

                if (!key.equals("class")) {

                    Object value = mp.get(key.toUpperCase());
                    if (value != null&&value.toString().length()>0) {
                        Method setter = property.getWriteMethod();// Java中提供了用来访问某个属性的
                        property.getPropertyType();

                        Type[] ts = setter.getGenericParameterTypes();
                        // 只要一个参数
                        String xclass = ts[0].toString();

                        if (xclass.equalsIgnoreCase("class java.lang.String")) {
                            setter.invoke(t, value.toString());
                        } else if (xclass.equalsIgnoreCase("class java.util.Date")) {

                            setter.invoke(t, DateUtil.parseStrToDate(value.toString(),
                                    DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI));
                        } else if (xclass.equalsIgnoreCase("class java.lang.Boolean")) {

                            if (value.equals("否")) {
                                setter.invoke(t, false);
                            } else {
                                setter.invoke(t, true);
                            }

                        } else if (xclass.equalsIgnoreCase("class java.lang.Integer")||xclass.equalsIgnoreCase("int")||xclass.equalsIgnoreCase("Integer")) {
                            setter.invoke(t, Integer.parseInt(value.toString()));
                        }

                        else if (xclass.equalsIgnoreCase("class java.lang.Long")||xclass.equalsIgnoreCase("long")) {
                            setter.invoke(t, Long.parseLong(value.toString()));
                        } else if (xclass.equalsIgnoreCase("class java.lang.Double")||xclass.equalsIgnoreCase("double")) {
                            setter.invoke(t, Double.parseDouble(value.toString()));
                        } else if (xclass.equalsIgnoreCase("class java.lang.Float")||xclass.equalsIgnoreCase("float")) {
                            setter.invoke(t, Float.parseFloat(value.toString()));
                        }

                        else {

                            // getter/setter方法
                            setter.invoke(t, value);
                        }
                    }
                }

            }

        } catch (IntrospectionException e) {

            e.printStackTrace();
        }
        return t;
    }




}
